package com.zys.background.auth.extension;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author zys
 * @since 2022-11-21
 */
@Component
@SuppressWarnings("AlibabaServiceOrDaoClassShouldEndWithImpl")
public class UserDetailsManager extends JdbcDaoImpl implements UserDetailsService {

  private static final String USERS_BY_USERNAME_QUERY = "select username, password from sys_user where username = ? and deleted = 0";
  private static final String ROLES_BY_USERNAME_QUERY = "select r.role_id, r.role_key from sys_role r "
      + "left join sys_user_role ur on r.role_id = ur.role_id "
      + "left join sys_user u on u.user_id = ur.user_id "
      + "where u.username = ?";

  private static final String PERMISSIONS_BY_USERNAME_QUERY = "select m.permission from sys_menu m "
      + "left join sys_role_menu rm on m.menu_id = rm.menu_id "
      + "where m.permission is not null and rm.role_id in (?) ";

  public UserDetailsManager(JdbcTemplate jdbcTemplate) {
    super.setUsersByUsernameQuery(USERS_BY_USERNAME_QUERY);
    super.setJdbcTemplate(jdbcTemplate);
  }
  @Override
  protected List<UserDetails> loadUsersByUsername(String username) {
    Assert.notNull(getJdbcTemplate(),"getJdbcTemplate() not allow null");
    return getJdbcTemplate().query(getUsersByUsernameQuery(), this::mapToUser, username);
  }

  @Override
  protected List<GrantedAuthority> loadUserAuthorities(String username) {
    Assert.notNull(getJdbcTemplate(),"getJdbcTemplate() not allow null");
    ArrayList<Long> roleIds = new ArrayList<>();
    List<SimpleGrantedAuthority> roles = getJdbcTemplate().query(
        ROLES_BY_USERNAME_QUERY,
        (rs, rowNum) -> {
          roleIds.add(rs.getLong(1));
          return new SimpleGrantedAuthority(rs.getString(2));
        },
        username);
    Set<GrantedAuthority> dbAuthsSet = new HashSet<>(roles);
    if (!roleIds.isEmpty()) {
      List<SimpleGrantedAuthority> authorities = getJdbcTemplate().query(
          PERMISSIONS_BY_USERNAME_QUERY,
          (rs, rowNum) -> new SimpleGrantedAuthority(rs.getString(1)),
          roleIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
      dbAuthsSet.addAll(authorities);
    }

    return new ArrayList<>(dbAuthsSet);
  }

  private UserDetails mapToUser(ResultSet rs, int rowNum) throws SQLException {
    String username = rs.getString(1);
    String password = rs.getString(2);
    List<GrantedAuthority> grantedAuthorities = loadUserAuthorities(username);
    return new User(username, password, true, true, true, true, grantedAuthorities);
  }
}
